package com.ecmcloud.flow.config;

import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.StrUtil;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import com.ecmcloud.common.utils.JsonMapperUtils;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Aspect
@Component
public class LogAop {

	/**
	 * 请求耗时报警时间
	 */
	@Around("(@annotation(org.springframework.web.bind.annotation.GetMapping)"
			+ "||@annotation(org.springframework.web.bind.annotation.PostMapping)"
			+ "||@annotation(org.springframework.web.bind.annotation.PutMapping)"
			+ "||@annotation(org.springframework.web.bind.annotation.RequestMapping)"
			+ "||@annotation(org.springframework.web.bind.annotation.DeleteMapping))" + "")
	@SneakyThrows
	public Object writeLog(ProceedingJoinPoint point) {
		Object target = point.getTarget();
		String className = target.getClass().getName();
		Object[] args = point.getArgs();

		Object proceed = null;
		Signature signature = point.getSignature();
		MethodSignature methodSignature = (MethodSignature) signature;
		
		Method method = methodSignature.getMethod();
		com.ecmcloud.common.config.NotWriteLogAnno notWriteLogAnno = method.getAnnotation(com.ecmcloud.common.config.NotWriteLogAnno.class);
		if (notWriteLogAnno != null && notWriteLogAnno.exclude()) {
			return point.proceed(args);
		}
		if (StrUtil.equals(method.getName(), "error")) {
			return point.proceed(args);
		}
		String[] parameterNames = methodSignature.getParameterNames();
		Map<String, Object> paramMap = new HashMap<>();
		int length = parameterNames.length;
		for (int i = 0; i < length; i++) {
			paramMap.put(parameterNames[i], args[i]);
		}
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		try {
			if (notWriteLogAnno == null || !notWriteLogAnno.all()) {
			    if (notWriteLogAnno != null) {
			        String[] paramsExclude = notWriteLogAnno.paramsExclude();
			        for (String p : paramsExclude) {
			            paramMap.remove(p);
			        }
			    }
			    log.info("入参   类: " + className + " 方法: " + method.getName() + " 参数: " + JsonMapperUtils.toJsonString(paramMap));
			}
			proceed = point.proceed(args);
			if (notWriteLogAnno != null && !notWriteLogAnno.printResultLog()) {
				return proceed;
			}
			stopWatch.stop();
			log.info("返回日志：{} 响应时间:{}", JsonMapperUtils.toJsonString(proceed), stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
			return proceed;
		} catch (Throwable throwable) {
			log.error(throwable.getMessage(), throwable);
			throw new RuntimeException(throwable);
		}
	}

}
